perm filename JUST[E,ALS]4 blob sn#229819 filedate 1976-08-11 generic text, type T, neo UTF8
;JCTAB PINXLT PARGET NEXTLI

COMMENT ⊗
Register assignments used in main section of JUST (and related routines)

	A	Input character pointer
	B	Input line address
	C	Current character
	D	Output character pointer
	E	Address of table defining data region
	F	Usual flag word
	G	Character count for output line (-x,,0 at start)
	H	Special flag word
	I	Address of line into which characters are going
	J	Input char count for TJ commands
	K	Output tab field termination position for TJ commands
	DSP	Current dispatch table address
	P	Stack pointer, as usual
	Q	Several counting jobs and to index TABOLD and TABTAB
	T	Temporary
	TT	Temporary
Special flag usage with F during JUST etc. (after initial normal usage)
  Right half of F
	NEG	set to 0 for JUST, to 1 for JFILL
	REL	set to 0 for no par. break, to 1 for par. break
  Left half of F
	TF1	used in JPREAD to keep neg sign info and then
		set to 0 foe first pass, to 1 for second pass in JUST
	TF2	set to 0 for JUST and JFILL, to 1 for TJUST and TFILL  
	TF3	set to 1 for JSTOP and JJSTOP commands 
End of comment ⊗

;Special flags tested against H (for use with JUST and related commands)

	JUSF←←200000	;CR, LF, VT, FF, SP, TAB, . ! ?
;	LSPC←←100000	;Special character, previously defined
;	NUMF←←40000	;Number			"	"
	JALL←←20000	;Dispatch on all characters
;	LETF←←10000	;Letter	(with LT2F => lower case)
;	LT2F←←4000	;Alone=> $ % . _
	JTBF←←2000	;TAB
	JCRF←←1000	;CR, LF, FF, VT

;Dispatch displacements used in following table

;	0	CR, LF, NUL and all disallowed chars. for in-core pages
;	1	TAB (11)
;	2	Space (40)
;	3	Sentence terminating punctuation . ? !
;	4	Closures ) ] > } "
;	5	All other normal characters

;Special character-dispatch table for use with JUST and related commands

JCTAB:	JALL!JUSF,,(DSP)		;NUL	0
	REPEAT 10<JALL,,5(DSP)>		;↓ α β ∧ ¬ ε π λ   1,2,3,4,5,6,7,10

	JALL!JUSF!JTBF!LSPC,,1(DSP)		;TAB	11
 	REPEAT 3,<JALL!JUSF!JCRF!LSPC,,(DSP)>  ;LF,VT,FF	12,13,14
	JALL!JUSF!JCRF!LSPC,,(DSP)		;CR	15
	JALL,,5(DSP)			;∞	16
	JALL,,5(DSP)			;∂	17

	REPEAT 20,<JALL,,5(DSP)>   ; ⊂ ⊃ ∩ ∪ ∀ ∃ ⊗ ↔ _ → ~ ≠ ≤ ≥ ≡ ∨  20 thru 37

	JALL!JUSF,,2(DSP)		;SP	40
	JALL!JUSF,,3(DSP)		;!	41
	JALL,,4(DSP)		;"	42
	REPEAT 5,<JALL,,5(DSP)>		;# % & '	43,44,45,46,47

	JALL,,5(DSP)			;(	50
	JALL,,4(DSP)		;)	51
	REPEAT 4,<JALL,,5(DSP)>		;* + , -	52,53,54,55
	JALL!JUSF,,3(DSP)		;.	56
	JALL,,5(DSP)			;/	57

	REPEAT 12,<JALL!NUMF,,5(DSP)>	;0,1,2,3,4,5,6,7,8,9	60 thru 71
	REPEAT 2,<JALL,,5(DSP)>	; : ;	72,73
	REPEAT 2,<JALL,,5(DSP)>		; < =	74,75
	JALL,,4(DSP)		; >	76
	JALL!JUSF,,3(DSP)		;?	77

	JALL,,5(DSP)			;@	100
	REPEAT 32,<JALL!LETF,,5(DSP)>	;A to Z	101 thru 132
	REPEAT 2,<JALL,,5(DSP)>		;[ \	133,134
	JALL,,4(DSP)		;]	135
	REPEAT 3,<JALL,,5(DSP)>		;↑ ← `	136,137,140

	REPEAT 32,<JALL!LETF!LT2F,,5(DSP)>  ;a th z	 141 thru 172
	JALL,,5(DSP)			;{	173
	JALL,,5(DSP)			;|	174
	JALL!JUSF!LSPC,,(DSP)		;ALT	175
	JALL,,4(DSP)		;}	176
	JALL!JUSF!NSPEC,,(DSP)		;RUBOUT	177

MINTXT←←3			;Minimum allowed text length or TAB field
TJSCNT←←2			;Minimum number of spaces to terminate a TAB field
TABCNT←←40			;Allow 32 tabs. NOTE: This number must not exceed
				;the size of BUF2

JPT1←←0
JPT2←←1
JETST←←2
JLPTR←←3
JCPTR←←4
JEXIT←←5

JPTAB:	ARRLIN
	,PAGE		;STUPID FAIL
	BOTSTR
	LINES
	CHARS
	PUSHJ P,LINSET
	JRST SETWRT

JATAB:	ATTBUF
	ATTBUF
	ATTBUF
	ATTNUM
	ATTSIZ
	MOVE T,ATTNUM
	CAILE T,ATTMAX
	MOVEI T,ATTMAX
	PUSHJ P,EXSET
	JRST ATTWRT

;  Locations to hold Margin specifications

	IMPURE
JSWTCH:	0		;Switch value to index SWTAB (set for N initially)
JSWTC2:	0		;Temporary value only
TJSWTC:	2		;Switch value for TABLE, TJUST and TJFILL (R initially)

PMAR:	4		;Paragraph margin indent
LMAR:	0		;Left justifying margin indent
RMAR:	=74		;Right justifying margin.
BNUM:	-1		;Number of blank lines between paragraphs


PMARO:	4		;Old values saved as old text indicators
LMARO:	0
RMARO:	=74
BNUMO:	-1

JPMAR:	0		;Values typed in with command
JLMAR:	0
JRMAR:	=74
JBNUM:	-1

JPMARO:	0
JLMARO:	0
JRMARO:	=74
JBNUMO:	-1

GPMAR:	0		;Values determined by JGETX
GLMAR:	0
GRMAR:	=74
GBNUM:	-1

TPMAR:	0
TLMAR:	0
TRMAR:	=74
TBNUM:	-1

TPMARO:	0
TLMARO:	0
TRMARO:	=74
TBNUMO:	-1

DTBCNT:	0
DSPCNT:	0

INMAR:	4
AMAR:	0

TABOLD:	BLOCK	TABCNT	;Old tabulations
	-1		;Guard cell
TABTAB:	BLOCK	TABCNT	;New tabulations
	-1		;Guard cell

RJMARS:	=80		;Sticky JOIN right margin allows room for some editing.
BREAKV:	=80		;Break value (always sticky)

;Memory locations to hold other variables
JCNT:	0	;Count of lines to be processed
JCNTC:	0	;Current value of JCNT during first pass
JPTR:	0	;Location of first line of text being processed
JPTRC:	0	;Location of first line of group currently being handled
JRPT:	0	;Next line after text being processed
JWCOL:	0	;Char count at last word break
JSCNT:	0	;Word break count
JBUGR:	0	;Bugger factor to distribute extra spaces
JWPT:	0	;Accumulated count of extra spaces added
JSINC:	0	;Needed spaces times 8
JSIZE:	0	;JSINC times number of breaks already processed
JMARG:	0	;Current output line's left margin
PARFLG:	0	;Set for new par. conditions as defined by PMARO, LMARO and BNUMO
;	Value assigned to PARFLG
;	0	means blank line needed to signal new par.
;	-1	means new par. every new line
;	+1	means new par if indent is >1
;	X>1	means new par. if indent is =X

	PURE
;J1DSP J2DSP J3DSP J4DSP J5DSP J6DSP J7DSP

;  Action on reaching a CR in the input text
J2CR:	TLNN F,TF1		;Is this the first pass
	JRST J2CR2		;Yes
	PUSHJ P,NEXTLI		;Finish off line and get next
	SOSG JCNT
	JRST J2CR5		;We should never get here, but just in case
	CAMN B,ARRLIS		;Does the data come from the original ARRLIN?
	MOVEM I,ARRLIS		;Yes, so change pointer
J2CR1:	MOVEI C,40		;Replace CR with a space and cont.
	SOS (P)			;To interpret the CR
	POPJ P,

;  First pass treatment
J2CR2:	SOSLE JCNTC
	JRST J2CR3
	TRO F,ARG		;Set end of text signal for second pass
	JRST J2CR4		;Treat end of text as end of par. here
J2CR3:	PUSHJ P,PARGET		;To get correct par info.
	TRNN F,REL
	JRST J2CR1		;No new par. so replace CR with space and continue
J2CR4:	TRO F,REL		;May enter here if end of data
	CAIN DSP,J1DSP		;Save data only after a non-space last char.
	JRST J2CR5
	AOS JSCNT		;Add to word break count
	HRRZM G,JWCOL		;Char count at this word break
J2CR5:	AOS (P)			;Forces an exit from loop without incrementing G
	POPJ P,

;   To eat all extra spaces and tabs
J1SP:	MOVNI C,3
	ADDM C,(P)		;This backs up to the ILDB command
	POPJ P,

;  Action at end of a word signalled by a space or tab
J2TAB:	MOVEI C,40
J2SP:	MOVEI DSP,J1DSP
	MOVSI H,JALL
J2SP1:	TLNE F,TF1	;Test for pass
	JRST J2SP2	;Second pass
	AOS JSCNT	;Add to word break count
	HRRZM G,JWCOL	;Char count to this word break
	POPJ P,

;  Second pass
J2SP2:	TRNN F,NEG!REL	;Is this line to be justified?
JUSPAD:	SKIPN T,JSINC		;8 times the needed number of extra spaces
	POPJ P,			;Exit if no extra spaces are required
;  To introduce extra spaces as required to justify
	ADDB T,JSIZE
	IDIV T,JSCNT		;Divide by available-location count
	ADD T,JBUGR		;Current bugger factor to distribute extra spaces
	LSH T,-3		;Divide by 8
	SUB T,JWPT		;JWPT counts additions to date
	ADDM T,JWPT
	JUMPE T,JUSPA2
JUSPA1:
LEG	IDPB C,D		;Add an extra space
	AOBJP G,JUSPA2		;Should always be negative
	SOJG T,JUSPA1
JUSPA2:	POPJ P,

;  Action on receipt of a sentence-terminating type punctuation mark
J2PUN:	MOVEI DSP,J3DSP
	MOVSI H,JALL
	POPJ P,

;  Action at end of sentence signalled by punctuation and space or tab
;  or by punctuation then a closure then a space or tab
J3TAB:	MOVEI C,40
J3SP:	MOVEI DSP,J1DSP
	TLNE F,TF1
	JRST J3SP2	;Its on the second pass
	AOS JSCNT	;Add to word break count
	HRRZM G,JWCOL	;Char count at this word break
	TLNE F,TF3
	JRST J3SP3	;Woops! make this a par break  
	AOBJN G,J3SP1	;Count for an extra space if possible
	SUB G,[1,,1]
J3SP1:	POPJ P,

J3SP2:
LEG	IDPB C,D	;Introduce second space always
	AOBJN G,J2SP2	;(should always be OK)
	POPJ P,		;Safety exit

J3SP3:	TRO F,REL	;Signal end of par
	AOS (P)		;Force exit from loop
	POPJ P,

;  Action on normal character if using JIDSP or J3DSP
J1CH:	MOVEI DSP,J2DSP
	MOVSI H,JUSF
	POPJ P,

;Special dispatch tables used with JCTAB (Table address in DSP)
; and using the above routines
;  After a space with JALL flag used
J1DSP:	PUSHJ P,J2CR	;CR
	PUSHJ P,J1SP	;TAB	(eaten)
	PUSHJ P,J1SP	;Space  (eaten)
	PUSHJ P,J1CH	;Punctuation	(MOVEI DSP,J2DSP↔MOVSI H,JUSF)
	PUSHJ P,J1CH	;Closure      		"		"    
	PUSHJ P,J1CH	;Other character	"		"

;  After a normal char. with JUSF flag used
J2DSP:	PUSHJ P,J2CR	;CR
	PUSHJ P,J2TAB	;TAB		(MOVEI DSP,J1DSP↔MOVSI H,JALL)
	PUSHJ P,J2SP	;Space			"		"
	PUSHJ P,J2PUN	;Punctuation	(MOVEI DSP,J3DSP↔MOVSI H,JALL)
	JFCL		;(Never used)
	JFCL		;(Never used)

;  After sentence-terminating punctuation with JALL flag used
J3DSP:	PUSHJ P,J2CR	;CR
	PUSHJ P,J3TAB	;TAB	(Replaced by space and handled as such)
	PUSHJ P,J3SP	;Space	(Introduces extra space and MOVEI DSP,J1DSP)
	JFCL		;Punctuation
	JFCL		;Closure
	PUSHJ P,J1CH	;Other character  (MOVEI DSP,J2DSP↔MOVSI H,JUSF)

;  CENTER, INDENT, ALIGN, etc. routines and dispatch tables

;  On finding a leading space
J4SP:	AOJA T,J1SP		;Count then eat

;  On finding the first non-space and non-tab
J4CH:	CAILE Q,5
	MOVEI Q,5
	JRST @J4CHD(Q)
J4CHD:	J4CH0		;Go to appropiate code as determined by Q
	J4CH1
	J4CH2
	J4CH3
	J4CH4
	J4CHX

;  Set desired margin
J4CHX:	MOVEI DSP,J5DSP
	MOVSI H,JTBF!JCRF
	PUSH P,C
	PUSHJ P,JMSTRT		;Start line with appropiate margin
	POP P,C
	POPJ P,

;  Get margin for INDENT
J4CH0:	ADD T,INMAR
	SKIPGE T
	SETZ T,
	JRST J4CHX

;  Get margin for CENTER
J4CH1:	SUB T,JWCOL		;Neg.of the number of text char. less initial spaces
	ADD T,JSIZE
	SKIPGE T
	SETZ T,
	LSH T,-1		;Divide by 2
	ADD T,LMAR
	JRST J4CHX

;  Get margin for ALIGN
J4CH2:	MOVE T,AMAR
	JRST J4CHX

;  Get margin for RTARR
J4CH3:	MOVE TT,INMAR
	SKIPG TT
J4CH3A:	MOVNS TT
J4CH3B:	ADD T,TT
	JUMPGE T,J4CHX
	SETZ T,
	JRST J4CHX

;  Get margin for LFARR
J4CH4:	MOVE TT,INMAR
	JUMPG TT,J4CH3A
	JRST J4CH3B

;  On finding a CR before any other non-space characters
J4CR:	MOVEI C,40
LEG	IDPB C,D
	AOS G
;  On finding a CR after some text
J5CR:	MOVEI DSP,J4DSP
	MOVSI H,JALL
	AOS (P)			;To skip the IDPB
	AOS (P)			;To exit from loop
	POPJ P,

;  On finding an interior TAB
J5TAB:	SKIPN JBUGR
	JRST J1SP		;Eat it in this case
LEG	IDPB C,D		;Write out first TAB when found
	MOVSI T,1		;TAB counts 1 in left of TXTCNT
	ADDM T,TXTCNT(I)
	HRRZ T,TXTCNT(I)	;Columns already accounted for
	HRRZ TT,G		;Column count accumulating in G
	ADD T,TT		;The actual column position
	ANDI T,7		;modulo 8
	MOVEI TT,10
	SUB TT,T
	ADDM TT,TXTCNT(I)
	MOVEI T,40
J5TAB2:
LEG	IDPB T,D
	SOJG TT,J5TAB2
LEG	IDPB C,D		;Closing TAB
J5TAB3:	ILDB C,A
	CAIN C,40
	JRST J5TAB3		;Eat the spaces
	CAIN C,11		;Look for the closing TAB
	JRST J1SP		;Eat it and go on
	SOS (P)
	SOS (P)			;Take a look at this character!
	POPJ P,			;Should never get here, but just in case


;  Initial dispatch table to eat spaces and tabs
J4DSP:	PUSHJ P,J4CR	;CR	(An all space line, maybe it is wanted)
	PUSHJ P,J1SP	;TAB	(eaten)
	PUSHJ P,J4SP	;Space  (counted then eaten)
	PUSHJ P,J4CH	;Punctuation	(MOVEI DSP,J5DSP↔MOVSI H,JTBF)
	PUSHJ P,J4CH	;Closure      		"		"    
	PUSHJ P,J4CH	;Other character	"		"


;   In-text dispatch table to look for a TAB or a CR
J5DSP:	PUSHJ P,J5CR	;CR
	PUSHJ P,J5TAB	;TAB	(special treatment depending on JBUGR setting)
	JFCL
	JFCL
	JFCL
	JFCL
;PARGET NEXTLI ADJARG JNEW JMORE JUFIX JBLANK JMSTRT

;   Subroutine to get new par. indicator
PARGET:	MOVE A,JCNT
	CAIG A,1		;Is this the last line?
	JRST PARG2		;Yes
	HRRZ B,(B)
PARG0:	HRRZ T,TXTCNT(B)
	JUMPE T,PARG2
PARG1:	MOVE A,B
	ADD A,[440700,,LLDESC]
	TRZ F,REL		;Means no new par.
	MOVE T,A		;We will have to test new line indent
	SETZ TT,
PARG1A:	ILDB C,T		;Count leading spaces
	CAIN C,40
	AOJA TT,PARG1A
	CAIN C,11
	AOJA D,PARG1A
	TLNE F,TF2		;Was this a TABLE or TJ command?
	JRST PARG4
	SKIPN JSWTCH		;Is the N switch on?
	JRST PARG3		;Yes
	CAMN TT,LMARO
	POPJ P,			;Handles case where LMARO=PMARO
	CAMN TT,PMARO		;Indent must match for all other switch settings
PARG2:	TRO F,REL
	POPJ P,

PARG3:	CAILE TT,1		;N switch case, any indent >1 indicates new par
	TRO F,REL
	POPJ P,

;  TABLE or TJ case
PARG4:	SKIPGE TABFLG
	JRST PARG2		;TABLE uses TPMARO always
	SKIPN TJSWTC
	JRST PARG3
	CAMN TT,TLMARO
	POPJ P,			;Handles case where TLMARO=TPMARO
	CAMN TT,TPMARO		;Indent must match for all other switch settings
	TRO F,REL
	POPJ P,
	
;  For second pass when input line is exhausted
NEXTLI:	HLRZ T,TXTCNT(B)
	MOVNI T,(T)			;and do 1's complement of T
	ADDM T,@JCPTR(E)		;add this to # in CHARS or ATTSIZ.
	SOS @JLPTR(E)			;Subtract 1 from # in LINES or ATTNUM.
	MOVE A,B			;Old B value needed in A by FSGIVE
	HRRZ B,(B)			;Get line forward pointer
	MOVEM B,JPTR			;and put it in JPTR.
	MOVSI T,JPTR			;with JPTR location in left half
	HLLM T,(B)			;of pointer for line pointed to.
	PUSHJ P,FSGIVE			;Give up storage space. (saves B)
	MOVE A,B
	ADD A,[440700,,LLDESC]
	POPJ P,

;  Limit neg A so as not to back too far, MOVARR and set A pos
ADJARG:	MOVNS A
	CAMGE A,ARRL		;Are we trying to go back too far?
	JRST ADJAR1
	MOVE A,ARRL		;Yes
	SUBI A,1
ADJAR1:	PUSH P,A
	MOVNS A
	PUSHJ P,MOVARR		;Now back up
	MOVE T,WINLIN
	MOVSI TT,WINBIT
	ANDCAM TT,TXTFLG(T)
	SETZM WINLIN
	SETZM TOPWIN
ADJAR2:	POP P,A			;Get positive count back
	POPJ P,

;  Get space for first new line
JNEW:	PUSH P,Q
	HRRZ Q,(B)
	MOVEM Q,JRPT#		;Keep current next line address
	CAMN B,PAGE
	TRO F,UPDTXT		;This is the first line on the page
	HLLZ Q,TXTFLG(B)	;Save flags
	HRRZ I,FSEND
	ADDI I,1
	MOVEM I,JLPT
	HLLZ TT,(B)		;Use the left half of old link for
LEG	MOVEM TT,(I)		;left half of the new link word, zero right
	HLRZ T,TT
 	HRRM I,(T)		;Fix earlier forward link to the new line
LEG	HLLM Q,TXTFLG(I)	;Use old flags
	TLNE Q,ARRBIT		;May need to reset ARRLIN
	MOVEM I,ARRLIN
	TLNE Q,WINBIT		;and also WINLIN
	MOVEM I,WINLIN
	CAMN B,ARRLIS
	MOVEM I,ARRLIS		;Finally fix ARRLIS if necessary
	POP P,Q
	POPJ P,

;  Get space for next output line
JMORE:	HRRZ TT,FSEND		;So get space starting address
	ADDI TT,1
	HRRM TT,(I)		;Complete forward link in finished line
LEG	HRLZM I,(TT)		;and back link new line
	MOVEM TT,JLPT
	MOVE I,JLPT
	MOVEI TT,0
LEG	HRLM TT,TXTFLG(I)	;This should always be safe
	CAMN B,ARRLIS		;Does the data come from the original ARRLIN?
	MOVEM I,ARRLIS		;Yes, so replace by I
	POPJ P,


;  Introduce CRLF and finish off the line
JUFIX:	MOVEI C,15
LEG	IDPB C,D		;The CR
	MOVEI C,12
LEG	IDPB C,D		;And a LF
	TDZA C,C
LEG	IDPB C,D		;And a null
	TLNE D,760000
	JRST .-2
	MOVSI TT,2(G)		;2 for CRLF + char. count
	ADDI TT,(G)		;but only char. count into right half
	ADDM TT,TXTCNT(I)	;Record char counts
	AOS @JLPTR(E)		;Add to line count (LINES or ATTNUM)
	HLRZ T,TXTCNT(I)
	ADDM T,@JCPTR(E)	;Add to char count (CHARS or ATTSIZ)
	MOVE T,JLPT		;should be same as I
;Display text must be in ASCID
	ADDI T,LLDESC		;Get address of first text word
	MOVEI TT,1
	IORM TT,(T)		;Convert to ASCID
	CAIGE T,(D)
	AOJA T,.-2
	MOVEI TT,2(D)
	MOVSI T,TXTCOD
	FSFIX TT,T
	POPJ P,

;  To introduce a blank line
JBLANK:
LEG	HRRZS TXTFLG(I)		;Zero flg portion
LEG	SETZM TXTCNT(I)		;The 2,,0 will be added by JUFIX
	AOS TT,TXTNUM
LEG	HRRM TT,TXTSER(I)
	SETZ G,
	MOVE D,I
	ADD D,[440700,,LLDESC]
	MOVEI C,40
LEG	IDPB C,D
	PUSHJ P,JUFIX		;Finish off this line
	POPJ P,

;  To start new line with the proper margin
JMSTRT:	AOS TT,TXTNUM
LEG	HRRM TT,TXTSER(I)	;Assign I new serial number
	MOVE D,I		;Set up output char pointer
	ADD D,[440700,,LLDESC]
	IDIVI T,10		;See if TABs are to be used
LEG	HRLZM T,TXTCNT(I)	;Start new TXTCNT (with credit for any TABs)
	JUMPE T,J2PAS3		;No TABs
	PUSH P,Q		;Save Q
	MOVEI C,11
J2PAS0:
LEG	IDPB C,D
	MOVEI C,40
	MOVEI Q,10		;Temporary use only
	ADDM Q,TXTCNT(I)	;Count as displayed chars. only
J2PAS1:
LEG 	IDPB C,D
	SOJG Q,J2PAS1
	MOVEI C,11
J2PAS2:
LEG	IDPB C,D
	SOJG T,J2PAS0
	POP P,Q			;Restore Q
J2PAS3:	JUMPE TT,J2PAS5		;No extra spaces in JMARG
	HRR T,TT
	HRL T,TT
	ADDM T,TXTCNT(I)	;Count both as stored and as displayed
	MOVEI C,40
J2PAS4:
LEG	IDPB C,D
	SOJG TT,J2PAS4
J2PAS5:	POPJ P,
;JINIT JPREAD JMREAD JUDATA JUTYPO

;   To determine E and get corrected JCNT and JPTR values
JINIT:	TRNE F,ATTMOD		;Are we in ATTACH mode?
	SKIPA E,[JATAB]		;   Yes so put [JATAB] in E.
	MOVEI E,JPTAB		;   No so put [JPTAB] in E.
	MOVE D,@JPT1(E)		;Put contents of @ATTBUF or @ARRLIN in D.
	HRRZM D,JPTR#		;Location of first line to examine
	MOVE A,@JLPTR(E)		;Number of lines
	TRNE F,ATTMOD
	JRST JINIT2
	SUB A,ARRL
	ADDI A,1
JINIT2:	CAMGE A,JCNT
	MOVEM A,JCNT		;Limit number of lines to the available ones
	POPJ P,

JPREAD:	MOVE T,EXTPNT		;To read JPARAM changing instructions.
	MOVEM T,TYIPNT		;Set pointer.
	HRLI C,(<MOVEI C,>)
	MOVEM C,TYIINS
;  Subroutine to read typed-in decimal numbers.
;Returns the number in A, the terminating character in C and
;a count of the number of digits in B.
JPARAM:	SETZB A,B
	TLZ F,TF1
JPAR0:	PUSHJ P,TYI		;Get first character if any
	POPJ P,
	CAIN C," "
	JRST JPAR0		;Extra space allowed here
	AOS (P)			;Skip return if something typed
	CAIE C,"-"
	JRST JPAR2
	TLO F,TF1		;Signal for a neg number
JPAR1:	PUSHJ P,TYI		;Get next character
	JRST JPAR3		;End of typing
JPAR2:	CAIG C,71
    	CAIGE C,60
	JRST JPAR3		;Non numeric character
	IMULI A,12
	ADDI A,-"0"(C)
	AOJA B,JPAR1		;B used to indicate some number (may be zero)

JPAR3:	TLZE F,TF1
	MOVNS A
	POPJ P,

;   To read switches then 4 margin values with possible additional old values
JMREAD:	MOVSI Q,-4
	SETOM JPMAR(Q)
	SETOM JPMARO(Q)
	AOBJN Q,.-2
	SETOM JSWTC2
	MOVSI Q,-4
	PUSHJ P,JPREAD		;Get ready and read first parameter
	POPJ P,			;Nothing typed
	CAIG C,172
	CAIGE C,141
	SKIPA
	SUBI C,40		;Convert to upper case
	CAIG C,132
	CAIGE C,101
	JRST JMREA2		;No switch typed
	MOVEI T,3		;4 entries (one at 0) in SWTABL below
	CAMN C,SWTABL(T)
	SKIPA
	SOJGE T,.-2
	JUMPGE T,JMRES0
	OUTSTR [ASCIZ/Only N, G, R or E recognized./]
	JRST JMRES3

JMRES0:	MOVEM T,JSWTC2		;Save as new switch value

JMRES1:	PUSHJ P,JPARAM		;Switch was read so now go ahead with margins
	POPJ P,			;No margins typed
	MOVSI Q,-4
	CAIE C,40
	CAIN C,"/"
	JRST JMREA1		;Ignore a space or a / here
	CAIE C,","
	CAIN C,"!"
	JRST JMREA2
	CAIN C,15
	JRST JMREA2
	JRST JMRES2


SWTABL:	"N"			;Any indent >1 or blank line indicates new par.
	"G"			;Get old indent from text
	"R"			;Rejustify, previous output as input
	"E"			;Exact indent as specified earlier is required

SWNOTE:	OUTSTR [ASCIZ/Switch N (Normal, any indent >1) /]
	OUTSTR [ASCIZ/Switch G (Get from text) /]
	OUTSTR [ASCIZ/Switch R (Rejustify, previous output as input) /]
	OUTSTR [ASCIZ/Switch E (Exact old input indent = /]

SWNOTT:	OUTSTR [ASCIZ/Switch N (Normal, same as E for XTABLE) /]
	OUTSTR [ASCIZ/Switch G (Get from text) /]
	OUTSTR [ASCIZ/Switch R (Retabulate, previous output as input) /]
	OUTSTR [ASCIZ/Switch E (Exact old input conditions /]


JMREA0:	SKIPE B
	MOVEM A,JPMARO(Q)	;Correct old value
JMREA1:	PUSHJ P,JPARAM		;Read a parameter
	POPJ P,			;Nothing typed
JMREA2:	CAMN C,"|"		;Was a "|" separater used, meaning JPMARO (old)
	JRST JMREA0		;No
	SKIPE B			;B=0 means no number before symbol
	MOVEM A,JPMAR(Q)
	CAIE C,40		;A space or a comma may be used
	CAIN C,","		;Any other symbol terminates JGINIT
	AOBJN Q,JMREA1
	CAIN C,15
	POPJ P,
JMRES2:	CAIN C,";"
	TLNN F,TF2
	SKIPA
	POPJ P,
	OUTSTR [ASCIZ/Illegal syntax. /]
JMRES3:	OUTSTR [ASCIZ/ Command aborted. /]
	SETZM TYIPNT		;Ignore rest of command
	POP P,C
	JRST POPJ1
	POPJ P,

JUDATA:	MOVE T,JSWTCH
	SKIPE JCNT		;Do not change if inquiry only
	CAIE T,2
	JRST JUS4
;  G switch case
JUS3:	PUSHJ P,JGMAR		;Get values from text
	SETOM BNUMO
	MOVSI Q,-3
	MOVE T,GPMAR(Q)
	MOVEM T,PMARO(Q)
	AOBJN Q,.-2
	JRST JUS5

JUS4:	CAIE T,3
	JRST JUS5		;No change in PMARO for T switch
;  R switch case
	MOVSI Q,-4
	MOVE T,PMAR(Q)
	MOVEM T,PMARO(Q)	;Replace PMARO with PMAR values for R switch
	AOBJN Q,.-2
	JRST JUS5

;  Test to see if any changes were made
JUS5:	MOVSI Q,-3
	SKIPL JPMAR(Q)
	SETOM BNUM		;If BNUM not respecified when other changes
	AOBJN Q,.-2
	MOVSI Q,-4
JUS6:	SKIPL T,JPMARO(Q)
	MOVEM T,PMARO(Q)
	SKIPL T,JPMAR(Q)
	MOVEM T,PMAR(Q)
	AOBJN Q,JUS6
	POPJ P,

;  To report on switches and margins
JUTYPO:	MOVE T,JSWTCH
	XCT SWNOTE(T)		;OUTSTR appropiate note
	CAIE T,3
	JRST JUTYP1
	TYPDEC PMARO
	OUTSTR [ASCIZ/) /]
JUTYP1:	SKIPL BNUM
	JRST JUTYP2
	OUTSTR [ASCIZ/Margins are (P,L,R) /]
	MOVSI Q,-3
	JRST JUTYP3

JUTYP2:	OUTSTR [ASCIZ/Margins are (P,L,R,B) /]
	MOVSI Q,-4
	SKIPA
	OUTSTR [ASCIZ/,/]
JUTYP3:	TYPDEC PMAR(Q)
	AOBJN Q,.-2
	OUTSTR [ASCIZ/. /]
	POPJ P,
;TJIDSP TJ1DSP TJFILL TJUST TJDATA TJU1

;  To terminate on a CR
TJ1CR:	TLNE F,TF1		;Is this the first pass?
	JRST TJ1CR4		;No
	PUSHJ P,PARGET		;Is next line to be considered?
	TRNN F,REL
	JRST TJ1CR2		;Yes
	HRRZM G,JWCOL		;For the second pass
	JRST JU3D

;  Allow space to end of tab field
TJ1CR2:	CAILE K,(G)
	AOBJN G,TJ1CR2
	SKIPG TT,TABTAB(Q)	;Are there any more fields?
	JRST JU2		;Let the main routine handle any remaining text
	HRRZ K,TT
	AOS Q
	JRST TJ1CR2		;Allow space for them also

TJ1CR3:	AOS JSCNT		;Can count for a word break if necessary
	HRRZM G,JWCOL		;Used to reset G on the second pass
	JRST JU2

;  Second pass
TJ1CR4:	TRNE F,REL
	JRST JU4A		;We are through
	MOVEI C,40
	MOVEI DSP,J1DSP
	MOVSI H,JALL
	JRST JU4

;  To keep odd-even count on tabs and to eat them
TJ1TAB:	MOVNS ODDEVN#
	JRST J1SP	;MOVNI C,3↔ADDM C,(P)↔POPJ P,

;  To exit from loop, on a non-space via TJ1DSP or on two spaces via TJ2DSP
TJ1CH:	AOS (P)
	AOS (P)
	POPJ P,

TJ2TAB:	ADD A,[70000,,0]	;Back up so odd-even count will work
	CAIG A,0
	SUB A,[430000,,1]
	SOJA J,TJ2SP1		;Correct for the AOJ which follows

;  To test if there is more than 1 space (indicating the end of an entry)
TJ2SP:	MOVE TT,A
	ILDB C,TT	;Sneak look at the next character
	CAIE C,40
	CAIN C,11
	JRST TJ2SP1
	MOVEI C,40
	POPJ P,		;Single spaces are allowed in tab fields
TJ2SP1:	TLNN F,TF1	;Which pass?
	JRST TJ2SP2
	MOVEI C,40	;It could have been a tab
LEG	IDPB C,D
LEG	IDPB C,D
	AOS (P)		;For the extra instruction in second-pass loop
TJ2SP2:	AOBJN G,.+1	;Count only 1 here and save second count until later
	AOS J		;Also account for only 1 input char
	AOS (P)		;to exit from loop
	POPJ P,

;  Dispatch table to eat to next tab field
TJ1DSP:	JRST TJ1CR	;CR
 	PUSHJ P,TJ1TAB	;TAB	(odd-even checked then eaten)
	AOS J 		;Space  (counted to TABENO)
	PUSHJ P,TJ1CH	;Punctuation	(exit from loop)
	PUSHJ P,TJ1CH	;Closure	 "	"   "
	PUSHJ P,TJ1CH	;Other character  "	"   "

;   In-text dispatch table to look for a TAB or a CR
TJ2DSP:	JRST TJ1CR	;CR
	PUSHJ P,TJ2TAB	;TAB
	PUSHJ P,TJ2SP	;SP
	JFCL
	JFCL
	JFCL

;  To reformat previously formatted files which have missing entries
TABLE:	SETOM TABFLG#		;Marks this as a TABLE command
	JRST TJUST0

;  To reformat tables with no missing entries (may have appended information)
TJFILL:	TROA F,NEG
TJUST:	TRZ F,NEG
	SETZM TABFLG		;Marks these as TJF or TJU commands
TJUST0:	TLO F,TF2		;Signal that this is a T type command
	TLZ F,TF3		;But not a JSPLIT
	MOVEM A,JCNT		;Temporary value only
	PUSHJ P,JMREAD		;Read typed margin values
	SKIPGE T,JSWTC2		;Was switch setting changed?
	JRST TJUS2
	SKIPL TABFLG
	JRST TJUS1
	JUMPG T,TJUS1
	OUTSTR [ASCIZ/Only G, R and E switches work with XTABLE. Command aborted. /]
	SETZM TYIPNT
	POP P,C
	JRST POPJ1

TJUS1:	MOVEM T,TJSWTC
TJUS2:	PUSHJ P,TJREAD
	SKIPE JCNT		;Is this for real or for show?
	JRST JUST2
	PUSHJ P,TJDATA
	PUSHJ P,TJTYPO
	JRST POPJ1


TJDATA:	MOVE T,TJSWTC
	SKIPN JCNT
	JRST TJU5
	CAIE T,1
	JRST TJUS4
;  G switch case
TJUS3:	PUSHJ P,JGMAR
	SETOM TBNUMO
	MOVSI Q,-3
	MOVE T,GPMAR(Q)
	MOVEM T,TPMARO(Q)
	AOBJN Q,.-2
	MOVSI Q,-TABCNT
	MOVE T,TABTAB(Q)	;We want to change TABOLD and keep TABTAB
	EXCH T,TABOLD(Q)	;but TJG1 resets TABTAB fron the text so
	MOVEM T,TABTAB(Q)	;this double switch does it
	AOBJN Q,.-3
	PUSHJ P,TJG1		;Get TABTAB values from text
	MOVSI Q,-TABCNT
	MOVE T,TABTAB(Q)
	EXCH T,TABOLD(Q)
	MOVEM T,TABTAB(Q)
	AOBJN Q,.-3
	JRST TJUS5

TJUS4:	CAIE T,2
	JRST TJUS5
;  R switch case
	MOVSI Q,-4
	MOVE T,TPMAR(Q)
	MOVEM T,TPMARO(Q)
	AOBJN Q,.-2
	HRLI T,TABTAB
	HRRI T,TABOLD
	BLT T,TABOLD+TABCNT-1
TJUS5:	SKIPN TJRFLG		;Were some TABTAB changes made?
	JRST TJUS5A
	HRLI T,BUF2
	HRRI T,TABTAB
	BLT T,TABTAB+TABCNT-1
TJUS5A:	MOVSI Q,-4
	SKIPGE JPMARO(0)
	SKIPL JPMAR(Q)
	JRST TJUS6		;At least 1 value changed
	AOBJN Q,.-3
	JRST TJUS7A

TJUS6:	SETOM TBNUM		;Default value unless specified
	MOVSI Q,-4
TJUS7:	SKIPL T,JPMAR(Q)
	MOVEM T,TPMAR(Q)
	SKIPL T,JPMARO(Q)
	MOVEM T,TPMARO(Q)  
	AOBJN Q,TJUS7
	SETOM TJRFLG
TJUS7A:	SKIPN TJRFLG
	POPJ P,
TJUS8:	MOVE TT,TPMAR		;Start TJADJ off right
	PUSHJ P,TJADJ		;Adjust them
	POPJ P,

;  Special treatment if new par for TJ case
TJU1:	SETZB Q,J
	SKIPG TABOLD(Q)		;Are tab fields expected?
	JRST JU2		;No
TJU1A:	MOVE K,TPMAR
	MOVEM K,TABEND#
	TLNE F,TF1		;Which pass?
	JRST TJU1B
	TRZ F,REL		;Must be redetermined during first pass
	SKIPGE TABFLG
	TRO F,REL		;All lines are table lines for TABLE command
	SETOM TF2FLG#		;Signalling first pass on a table line
TJU1B:	SETOM ODDEVN		;To keep odd-even check on tabs
	MOVEI TT,77777
	SKIPGE TABFLG		;Is neg for TFJ commands
	MOVE TT,TPMARO
	MOVEM TT,TABENO#
	JUMPE TT,TJU3B
TJU2:	MOVEI DSP,TJ1DSP
	MOVSI H,JALL
	
;  Space eating loop (for both passes)
TJU3:	ILDB C,A		;Eat spaces, odd-even check tabs, to next field
TJU3A:	TLNE H,JCTAB(C)
	XCT @JCTAB(C)
	CAMGE J,TABENO
	JRST TJU3

	CAML J,TABENO		;Did we arrive at an entry too soon?
	JRST TJU3B		;No
	ADD A,[70000,,0]	;Yes, so back up
	CAIG A,0
	SUB A,[430000,,1]
	JRST TJU3C

TJU3B:	SKIPG ODDEVN		;Is there an unmatched tab?
	JRST TJU3C		;No
	MOVE T,A
	ILDB C,T		;Sneak look at next char
	CAIE C,11
	JRST TJU3C		;Must be char for next field
	ILDB C,A		;Eat it
	MOVNS ODDEVN		;and account for it
TJU3C:	TLNE F,TF1
	JRST TJU6		;Second pass
	SKIPLE TT,TABOLD(Q)
	JRST TJU4D		;Can continue
;  Out of tab fields but is there any text on this line?
	MOVE T,A
TJU4A:	ILDB C,T
	CAIE C,40
	CAIN C,11
	JRST TJU4A		;Eat spaces and tabs
	CAIE C,15
	CAIN C,12
	JRST TJU4C		;End of this input line
TJU4B:	CAILE K,(G)
	AOBJN G,TJU4B
	JRST JU2		;Go read the text

TJU4C:	PUSHJ P,PARGET
	TRNN F,REL
	JRST TJU4B		;There is text on the next line
	HRRZM G,JWCOL		;Character count for second pass
	SETZ JSINC		;To suppress any attempt to justify if no text
	JRST JU3B		;Go to second pass


TJU4D:	JUMPE Q,TJU4F		;Initial indent is handled differently
	CAILE K,(G)
	AOBJN G,.-1		;Allow for the normal field length
TJU4F:	SKIPGE TABFLG
	HRRZM TT,TABENO		;New input field end
	HRRZ K,TABTAB(Q)	;Establish the new output field termination
	SUB K,TPMAR		;Remember that G right is to measure from TPMAR
	JUMPG Q,TJU4E
	TLNN F,TF1
	HLLZS G			;First time fix so that G measures from TPMAR
TJU4E:	AOS Q
	MOVEI DSP,TJ2DSP
	MOVSI H,JUSF

;  First pass character count
TJU5:	ILDB C,A
	TDNE H,JCTAB(C)
	XCT @JCTAB(C)
	AOJA J,TJU5A		;Count input character and JUMP
	AOBJN G,TJU2		;Count second space here
	MOVEI DSP,J1DSP
	MOVSI H,JALL
	JRST JU2		;Let normal JUST or JFILL routine handle it

;  Normal character portion of loop
TJU5A:	AOBJN G,TJU5		;Account for normal character
	MOVEI DSP,J2DSP
	MOVSI H,JUSF
	JRST JU3A1

TJU6:	SKIPLE TT,TABOLD(Q)
	JRST TJU8
;  There may be text to follow
	MOVE T,A
TJU6A:	ILDB C,T
	CAIE C,40
	CAIN C,11
	JRST TJU6A		;Eat spaces and tabs
	CAIE C,15
	CAIN C,12
	JRST TJU7C		;End of this input line
TJU7:	MOVEI C,40		;Pad out with spaces to end of this field
TJU7A:	CAIG K,(G)
	JRST TJU7B
LEG	IDPB C,D
	AOBJN G,TJU7A

TJU7B:	MOVEI DSP,J1DSP		;Go read text
	MOVSI H,JALL
	JRST JU4

TJU7C:	TRNN F,REL		;Are we to go to the next line?
	JRST TJU7		;Yes
	JRST JU4A		;No, we are through

TJU8:	JUMPE Q,TJU8B		;First indent handled by J2PASS
	MOVEI C,40		;Pad out with spaces to next field start
TJU8A:	CAIG K,(G)
	JRST TJU8B
LEG	IDPB C,D
	AOBJN G,TJU8A
TJU8B:	SKIPGE TABFLG
	HRRZM TT,TABENO		;New input field end
	HRRZ K,TABTAB(Q)
	SUB K,TPMAR		;Remember that G is measured from TPMAR
	AOS Q
	MOVEI DSP,TJ2DSP
	MOVSI H,JUSF

;  Second pass character transfer
TJU9:	ILDB C,A
	TDNE H,JCTAB(C)
	XCT @JCTAB(C)
LEG	IDPB C,D
	AOJA J,TJU9A		;Count input character and JUMP
	AOBJN G,TJU2		;Count second space here
	JRST JU4A


TJU9A:	AOBJN G,TJU9		;Count transfered character
	JRST JU4A
;JSEPAR JJSEPA JFILL JUST

;  To separate text into individual sentences, either filled or justified
JSEPAR:	TROA F,NEG
JJSEPA:	TRZ F,NEG
	TLZ F,TF2
	TLO F,TF3
	JRST JUST0

;  To left margin justify and, alternatively, to justify both margins
JFILL:	TROA F,NEG		;For JFILL case
JUST:	TRZ F,NEG		;For JUST case
	TLZ F,TF2!TF3		;Neither a TJ nor a JS command
JUST0:	MOVEM A,JCNT		;Preliminary value only
	PUSHJ P,JMREAD		;Read switch and typed margin values
	CAIN C,15
	JRST JUST2A
	OUTSTR [ASCIZ/Too many characters! Command aborted./]
	SETZM TYIPNT
	JRST POPJ1


JUST2A:	SKIPL T,JSWTC2
	MOVEM T,JSWTCH
	SKIPE JCNT		;Is this for real or for show?
	JRST JUST2
	PUSHJ P,JUDATA		;Accept typed values only
	PUSHJ P,JUTYPO		;and report
	JRST POPJ1

JUST2:	PUSHJ P,ENDSET		;So new data will be at end of FS
	TLO F,NOCHK		;Don't CORE DOWN untill through
	MOVE A,ARRLIN
	MOVEM A,ARRLIS#		;Save so we can reset arrow when done
	MOVE A,TOPWIN
	MOVEM A,TOPWIS#
	MOVE A,JCNT
	TRNN F,ARG!ATTMOD
	JRST JU0A		;Start at beginning of page and do entire page
	TRNN F,ARG
	JRST JU0B		;Do entire ATTACH buffer
	TRNN F,ATTMOD
	JRST JU0		;Still have to worry about a neg arg
	JUMPG A,JU1
	MOVNS A			;Neg argument if attached has no meaning
	JRST JU1

JU0:	JUMPG A,JU1
	PUSHJ P,ADJARG		;Adjust A to start earlier and do thru init. ARRL
	JRST JU1

JU0A:	PUSHJ P,SETARR		;Start at beginning of page
	MOVE T,WINLIN
	MOVSI TT,WINBIT
	ANDCAM TT,TXTFLG(T)
	SETZM WINLIN
	SETZM TOPWIN
JU0B:	MOVEI A,-1
JU1:	MOVEM A,JCNT		;Tentative line count
	TRZ F,ARG		;This is used later to signal the end of data
	PUSHJ P,JINIT		;Set E, get JPTR, and correct JCNT value
;  Now we can interpret the switch and fix the margins
	TLNE F,TF3
	JRST JU1X		;A JSeparate command
	TLNE F,TF2
	PUSHJ P,TJDATA		;A TAble or TJ command
	TLNN F,TF2
	PUSHJ P,JUDATA		;JUST or JFILL
;  Procede with justification
JU1X:	MOVSI H,JALL		;Set to dispatch on all characters
	MOVEI DSP,J1DSP		;Set dispatch for new output line
	MOVE B,JPTR
	TRZ F,REL		;Means not new par. on first pass
	TLNE F,TF2		;But is it a XTA OR XTJ command?
	TRO F,REL		;Yes, first line considered new par.
	SETZM JBUGR		;Bugger factor that staggers inserted spaces
JU1A:	HRRZ C,TXTCNT(B)	;Is this line blank?
	JUMPN C,JU1B		;No
	HRRZ B,(B)		;Skip over it
	MOVEM B,JPTR		;Initial blank lines are left but signal new par
	SOSG JCNT		;One less line to process
	JRST JU8
	TRO F,REL		;Means new par. indent to start
	JRST JU1A

JU1B:	PUSHJ P,JNEW		;Get space for new lines and fix flags etc.
	TRNN F,REL		;Alrready know that new par. indent is to be used
	PUSHJ P,PARG0		;Is this the start of a par?
JU1C:	MOVE A,B
	ADD A,[440700,,LLDESC]
JU1D:	TLNE F,TF2		;Was this a TJ command
	JRST JU1E		;Yes
;  Get normal margins
	MOVE G,LMAR
	TRNE F,REL		;No new par indent if 0
	MOVE G,PMAR
	MOVEM G,JMARG		;Save as current margin for second pass
	SUB G,RMAR
	JRST JU1F

;  Get TJ margins
JU1E:	MOVE G,TLMAR
	TRNE F,REL		;No new par indent if 0
	MOVE G,TPMAR
	MOVEM G,JMARG		;Save as current margin for second pass
	SUB G,TRMAR
JU1F:	MOVNM G,JSIZE		;The expected size of new line less margin
	SUBI G,1		;Go 1 char. beyond on the first pass
	HRLZS G
	MOVEM A,ASAVE
	SETZM JSCNT		;To count word separators
	MOVE C,JCNT
	MOVEM C,JCNTC
	TLNE F,TF2
	TRNN F,REL
	SKIPA
	JRST TJU1		;Go to TJ routine if TJ command and new par
JU2:	MOVEI DSP,J1DSP		;Always eat initial spaces
	MOVSI H,JALL
	TLZ F,TF1		;Set for first pass
	TRZ F,REL		;Must be redetermined during first pass 
;First pass
;   Determine accepted-char. count, # of word separators and par. conditions
JU3:	ILDB C,A
	TDNE H,JCTAB(C)
	XCT @JCTAB(C)		;Caution, return may be .-2, ., .+1 or .+2
	AOBJN G,JU3

JU3A1:	SKIPN JSCNT		;Have we come to a word break?
	JRST JU3		;Impossible to break line so go on
JU3AA:	SETZM JSINC		;Safety precaution only
;  Verify par. conditions
	TRNE F,REL		;Have we already determined par. conditions?
	JRST JU3D		;Yes
	LDB C,A			;GET last char. back
	CAIN C,15		;Was it a CR?
	JRST JU3B		;YES, so no further testing needed
	SKIPA
JU3A:	ILDB C,A
	CAIE C,40
	CAIN C,11
	JRST JU3A		;Eat all spaces and TABs
	CAIE C,15		;Now do we find a CR?
	JRST JU3B		;No, so some text is left
	PUSHJ P,PARGET		;Yes, so look at next line
JU3B:	TRNN F,NEG!REL		;Is this a JFILL or a last line of par.
	SOSG JSCNT		;Do not count final word ending
	JRST JU3D		;Line must be left un-justified
;  Prepare for justification
	MOVE T,JSIZE
	SUB T,JWCOL
	LSH T,3			;Multiply by 8
	MOVEM T,JSINC
	MOVN G,JSIZE
	SETZM JSIZE		;Used in the JUSPAD routine for accumulated JSINC
	SETZM JWPT		;Used in JUSPAD for accumulated insertions
	SKIPA
JU3D:	MOVN G,JWCOL		;Un-justified case
	HRLZS G
;   Prepare for the second pass
	TLO F,TF1		;Set for second pass
	MOVE T,JMARG		;Get correct current margin value
	PUSHJ P,JMSTRT		;Start new line with this margin
	MOVE A,ASAVE
	MOVE B,JPTR
	MOVSI H,JALL
	MOVEI DSP,J1DSP		;Always eat initial spaces
	TLNE F,TF2
	SKIPL TF2FLG		;Is set to -1 on first pass of table line
	JRST JU4
	SETZM TF2FLG
	JRST TJU1		;For second pass on table line

;   Main character transfering loop
JU4:	ILDB C,A
	TDNE H,JCTAB(C)
	XCT @JCTAB(C)		;Caution, return may be to .-2, ., or .+1
LEG	IDPB C,D
	AOBJN G,JU4

JU4A:	PUSHJ P,JUFIX		;Fix up line just finished
	TRNE F,ARG		;Is text exhausted?
	JRST JU6D		;Yes
	TLZ F,TF1		;Get set for new first pass
	TLNE F,TF3		;Was it a JS command?
	JRST JU5E		;Yes
	TRNN F,REL		;Is it to be a new par?
	JRST JU6		;No
	TLNE F,TF2		;Is it a TJ command
	MOVE Q,TBNUM		;Yes, so use proper value
	TLNN F,TF2
	MOVE Q,BNUM
	JUMPLE Q,JU5B
JU5:	SOS Q
JU5A:	PUSHJ P,JMORE		;Get space
	PUSHJ P,JBLANK		;Introduce blank line
JU5B:	PUSHJ P,NEXTLI
	SOSG JCNT
	JRST JU7		;No more text
	HRRZ T,TXTCNT(B)
	JUMPN T,JU5C
	CAMN B,ARRLIS
	MOVEM I,ARRLIS
	JUMPG Q,JU5
	JUMPL Q,JU5A
	JRST JU5B

;  Special treatment for XJS command
JU5E:	TRZ F,REL		;Use LMAR indent always
	MOVE T,A
JU5F:	ILDB C,T		;Sneak look ahead
	CAIE C,40
	CAIN C,11
	JRST JU5F
	CAIE C,15
	JRST JU6		;Not a input line break
	MOVE T,B
	SETZ Q,
JU5G:	HRRZ T,(T)		;Sneak look at next line
	HRRZ TT,TXTCNT(T)
	SKIPG TT		;No blank line
	AOJA Q,JU5G
JU5C:	JUMPLE Q,JU6
JU5D:	PUSHJ P,JMORE
	PUSHJ P,JBLANK
	SOJG Q,JU5D
JU6:	PUSHJ P,JMORE
	JRST JU1D

JU6D:	PUSHJ P,NEXTLI		;Give up final old line
;Complete the links to the following text
JU7:	MOVE T,JLPT		;Now fix new right link
	HRRM B,(T)		;A references  next line
	HRLM T,(B)		;And backward link to the new line
	TRO F,WRITE!DSPALL
JU8:	PUSHJ P,ENDFIX
	TLZ F,NOCHK
	TRNE F,ATTMOD
	JRST JU9		;Arrow was not moved in this case
	MOVE B,PAGE	
	MOVEI A,1
JU8A:	CAMN B,ARRLIS
	JRST JU8B
	HRRZ B,(B)
	CAIE B,BOTSTR
	AOJA A,JU8A
	AOS A
JU8B:	PUSHJ P,SETARR
	MOVE A,TOPWIS
	PUSHJ P,SETWIN
JU9:	JRST JEXIT(E)
;IND INDENT CENTER ALIGN LFARR RTARR 

;  Common routine used by CENTER, INDENT etc. with proper dispatch value in DSP
IND:	SETZM JBUGR		;Normal case where TABs are replaced by spaces
	CAIE C,"T"		;Was the TAB flag typed?
	CAIN C,"t"
	SETOM JBUGR		;Signals retention of internal TABs
	PUSHJ P,ENDSET		;So new data will be at end of FS
	TLO F,NOCHK		;Don't CORE DOWN untill through
	MOVE A,ARRLIN
	MOVEM A,ARRLIS#		;Save so we can reset arrow when done
	MOVE A,TOPWIN
	MOVEM A,TOPWIS#
	POP P,A			;The initial argument saved by CENTER or INDENT
	TRNE F,ATTMOD
	JRST IND2
	JUMPGE A,IND3
	PUSHJ P,ADJARG		;Adjust argument and back up if neg
	JRST IND3

IND2:	SKIPGE A
	MOVNS A			;NEG value has no meaning if in ATTACH
	TRNN F,ARG
	MOVEI A,-1		;Do entire ATTACH buffer if no argument
IND3:	MOVEM A,JCNT		;Tentative count of lines to process
	PUSHJ P,JINIT		;Set E, get JPTR and correct JCNT
	MOVE B,JPTR
IND4:	HRRZ C,TXTCNT(B)	;Is this a blank line?
	JUMPN C,IND4A
	HRRZ B,(B)
	SOSG JCNT
	JRST JU8		;No non-blank lines (finish off as in JUST)
	JRST IND4		;Delay starting until first non-blank line

IND4A:	PUSHJ P,JNEW		;Get space for first line
IND5:	SETZ T,			;Used to count leading spaces
	MOVEM C,JWCOL		;Save character count for use in CENTER
	MOVE A,B
	ADD A,[440700,,LLDESC]
	MOVSI G,-77777
	MOVEI DSP,J4DSP
	MOVSI H,JALL
	SETZ T,

;  Main loop
IND6:	ILDB C,A
	TDNE H,JCTAB(C)
	XCT @JCTAB(C)
LEG	IDPB C,D
	AOBJN G,IND6

	PUSHJ P,JUFIX		;Add CRLF and finish off this line
IND7:	PUSHJ P,NEXTLI
	SOSG JCNT
	JRST JU7		;No more lines (finish as for JUST)
	PUSHJ P,JMORE		;Get space for nest line
	HRRZ C,TXTCNT(B)	;Is the next line blank?
	JUMPG C,IND5
	PUSHJ P,JBLANK		;Put in the blank line
	JRST IND7

INDENT:	PUSH P,A		;Will be restored in IND
	PUSHJ P,JPREAD
	SKIPA			;Use default value
	MOVEM A,INMAR
	MOVEI Q,0		;Signal to J4CH to use INDENT margin code
	JRST IND

CENTER:	PUSH P,A
	MOVSI Q,-4
	SETOM JPMAR(Q)
	AOBJN Q,.-1
	PUSHJ P,JMREAD		;Read typed margin values
	MOVSI Q,-4
CENT0:	SKIPL T,JPMAR(Q)
	MOVEM T,PMAR(Q)
	AOBJN Q,CENT0
	MOVE T,RMAR
	SUB T,LMAR
	MOVEM T,JSIZE		;Use for centering
	MOVEI Q,1		;Signal to J4CR to use CENTER margin code
	JRST IND		;use same routine as INDENT

;  ALIGN command aligns all specified lines at a fixed left margin
ALINE:
ALIGN:	PUSH P,A
	PUSHJ P,JPREAD
	JRST ALIGN2
	SKIPGE A
	SETZ A,
	MOVEM A,AMAR
ALIGN2:	MOVEI Q,2		;Signal to J4CH to use code for ALIGN
	JRST IND

;  Moves the specified lines right by the (absolute) INMAR value
RTARR:	PUSH P,A		;Will be restored in IND
	MOVEI Q,3
	JRST IND
	
;  Moves the specified lines left by the (absolute) INMAR value
LFARR:	PUSH P,A		;Will be restored in IND
	MOVEI Q,4
	JRST IND

JLEFT:	OUTSTR [ASCIZ/Not defined/]
	popj p,
;JGINIT JGB JGIND JGMAR JGET


;  Subroutine called by JGET and TJGET
;to clear PAR table and to read and store typed-in MAR values.
JGINIT:	TRNN F,ARG
	HRRZI A,-1		;Use rest of page (or buffer) if no argument
	MOVMM A,JCNT
	JUMPE A,JGIN1		;No text referencing
	MOVSI Q,-4
	SKIPN JCNT
	POPJ P,		 	;Leave old values if JCNT=0 and no typed value
	SETOM JPMAR(Q)
	AOBJN Q,.-1
	PUSHJ P,JINIT		;Set E and get proper JPTR and JCNT values
	MOVN G,JCNT
	HRLZS G
	MOVEM G,GSAVE#		;May be needed again later
JGIN1:	POPJ P,

;  Subroutine called by JGMAR
;Will locate the first non-blank line after 1 or  more blank lines and
;return the number of blank lines in B (B set to 0 before entry).
;Pointer to the first line of text in D and the specification of the number
;of lines of text (as a negative number) in the left of G.
JGB0:	HRRZ D,(D)
JGB:	HRRZ C,TXTCNT(D)
	JUMPN C,JGB1
	AOJA B,JGB2		;Count blank lines for JBNUM
JGB1:	CAMLE C,Q
	MOVE Q,C		;Put largest in Q for JRMAR
	JUMPE B,JGB2
	MOVEM B,GBNUM		;Save it here always
	MOVEM G,GSAVE		;May be needed twice
	MOVEM D,DSAVE#		;Save new starting place in text
	JRST JGB1B

JGB1A:	HRRZ D,(D)		;Go to end for Q determination
	HRRZ C,TXTCNT(D)
	CAMLE C,Q
	MOVE Q,C
JGB1B:	AOBJN G,JGB1B		;Are we at the end?
	MOVE G,GSAVE		;Reset for first line after blanks
	MOVE D,DSAVE
	POPJ P,			;Text found after a blank line

JGB2:	AOBJN G,JGB0		;Still looking
	MOVE D,JPTR		;No text found after blank line, so reset
	MOVE G,GSAVE
	SETZ B,			;Use B now to count lines having same indent
	MOVEM B,GBNUM		;This says no blank lines in text
JGB2A:	PUSHJ P,JGIND		;Get first line indent
	HRRZ TT,T		;Save it
JGB3:	AOBJP G,JGB4
	HRRZ D,(D)		;Try the next line
	PUSHJ P,JGIND
	CAIN TT,(T)
	AOJA B,JGB3		;Another line with the same indent
	JUMPE B,JGB4		;More than 1 line with same indent?
	MOVEM G,GSAVE
	MOVEM D,DSAVE
	POPJ P,

JGB4:	MOVE G,GSAVE		;Go back to first line if B still zero
	MOVE D,JPTR
	POPJ P,

;To get indentation
JGIND:	HRRZ T,TXTCNT(D)
	MOVNS T
	HRLZS T
	MOVE A,D
	ADD A,[440700,,LLDESC]
JGIND1:	ILDB C,A
	CAIN C,11		;Is it a TAB?
	JRST JGIND1		;Ignore it
	CAIN C," "		;Is it a space?
	AOBJN T,JGIND1		;Count it
	POPJ P,

;   Subroutine called by JGET and TJGET
;To determine margins from specified text
JGMAR:	MOVN G,JCNT
	HRLZS G
	MOVEM G,GSAVE		;May be needed twice
	SETZB B,Q		;B counts blank lines, Q gets JRMAR
	SETOM GBNUM
	MOVE D,JPTR		;Pointer to the first line of text
	PUSHJ P,JGB		;Find paragraph start
	PUSHJ P,JGIND		;Get its indentation
	MOVEM T,INDCNT#		;May be needed for TJGET case
	MOVEM A,ASAVE#		;and also pointer to first non-blank character
	HRRZM T,GPMAR
	AOBJN G,JGM0		;Trouble, not enough lines
	SETZM GBNUM		;Maybe he wants 1 paragraph
	JRST JGMA
JGM0:	HRRZ D,(D)
	PUSHJ P,JGIND		;Get indentation of the next line
JGMA:	HRRZM T,GLMAR
	MOVEM Q,GRMAR		;No, so save this value
	POPJ P,

;Get typed-in margins from the specified text.
JGET:	JUMPE A,JGET2
	PUSHJ P,JGINIT
	PUSHJ P,JGMAR		;Get margins by examining the text
	SETOM BNUM		;Default value used always with JGET
	MOVSI Q,-3
	MOVE T,GPMAR(Q)
	MOVEM T,PMAR(Q)
	AOBJN Q,.-2
JGET2:	OUTSTR [ASCIZ/Margins (P,L,R) from text are /]
	MOVSI Q,-3
	SKIPA
	OUTSTR [ASCIZ/,/]
JGET5:	TYPDEC PMAR(Q)
	AOBJN Q,.-2
	OUTSTR [ASCIZ/./]
	POPJ P,
;TJREAD TJADJ TJGET TJG1 TJTYPO

;  To read typed tab values
TJREAD:	SETZM TJRFLG
	CAIE C,";"
	CAIN C,"!"
	SKIPA
	POPJ P,			;No typed TAB values
	SETOM TJRFLG#
	HRLI T,TABTAB
	HRRI T,BUF2
	BLT T,BUF2+TABCNT-1	;Use BUF2 temporarily
	MOVSI Q,-TABCNT
	HLLZS BUF2(Q)		;Zero indent values only
	AOBJN Q,.-1

	MOVSI Q,-TABCNT
	CAIN C,"!"
	JRST TJR4		;Next number is to be an indent not a field size
TJR2:	PUSHJ P,JPARAM
	POPJ P,			;No more data
	CAIE C,"@"		;Is this a multiple define
	JRST TJR5
	MOVE H,A		;Yes, so save repetition number in H
	PUSHJ P,JPARAM		;and get field size
	SETZ A,			;No-value-typed return
	SKIPLE A		;A zero or missing value means leave unchanged
TJR3:	HRLZM A,BUF2(Q)
	AOBJP Q,TJR7		;No more space so ignore the rest
	SOJG H,TJR3
	JRST TJR6		;See if there are any more

TJR4:	PUSHJ P,JPARAM		;Get indent value
	SKIPA			;Syntax error
	JUMPG A,TJR4A		;An indent can not be zero
	OUTSTR [ASCIZ/IMPROPER SYNTAX, a non-zero number must follow a "!" symbol/]
	JRST TJR9

TJR4A:	HRRZM A,BUF2(Q)
	AOBJP Q,TJR7
	JRST TJR6

TJR5:	JUMPG A,TJR5A		;Was a number typed?
	CAIE C,"Z"
	CAIN C,"z"
	JRST TJR8
	SKIPA
TJR5A:	HRLZM A,BUF2(Q)		;Save it as a field length
	AOBJP Q,TJR7
TJR6:	CAIN C,","
	JRST TJR2
	CAIN C,"!"
	JRST TJR4
	CAIE C,"Z"
	CAIN C,"z"
	JRST TJR8
	CAIN C,15
	POPJ P,
	OUTSTR [ASCIZ/Improper syntax. Command aborted. /]
TJR9:	SETZM TYIPNT
	POP P,C
	JRST POPJ1

TJR7:	OUTSTR [ASCIZ/ Field table is full, will ignore rest. /]
TJR8:	SETOM BUF2(Q)
	SETZM TYIPNT
	POPJ P,

;  To adjust right half fields of TABTAB to reflect all typed changes
TJADJ:	MOVSI Q,-TABCNT		;Must be entered with margin value in TT
	HLLZS TABTAB(Q)
	AOBJN Q,.-1
	MOVSI Q,-TABCNT
TJADJ1:	SKIPG TABTAB(Q)
	JRST TJADJ4
	HLRZ T,TABTAB(Q)
	JUMPG T,TJADJ3		;A field length was specified
	HRRZ T,TABTAB(Q)	;An indent was specified
	SUB T,TT
	CAIL T,MINTXT
	JRST TJADJ2
	OUTSTR [ASCIZ/ TAB field #/]
	HRRZ C,Q
	TYPDEC C
	OUTSTR [ASCIZ/ set at min. length of /]
	MOVEI T,MINTXT
	TYPDEC T
	OUTSTR [ASCIZ/. /]
TJADJ2:	HRLM T,TABTAB(Q)
TJADJ3:	ADD TT,T
	HRRM TT,TABTAB(Q)	;May have been corrected
	AOBJN Q,TJADJ1
TJADJ4:	TRNN Q,777
	POPJ P,			;No fields specified
	CAMLE TT,TRMAR		;Was TRMAR large enough?
	MOVEM TT,TRMAR
	POPJ P,


;Get margins and TAB settings from text
TGET:
TJGET:	SETOM TABTAB
	HRLI T,TABTAB
	HRRI T,TABTAB+1
	BLT T,TABTAB+TABCNT-1
	PUSHJ P,JGINIT		;Initialize
	PUSHJ P,JGMAR		;Get margins by examining the text
	SETOM TBNUM
	SKIPG B
	MOVEM B,TBNUM
	MOVSI Q,-3
	MOVE T,GPMAR(Q)
	MOVEM T,TPMAR(Q)
	AOBJN Q,.-2
	PUSHJ P,TJG1		;Get tabular values
	PUSHJ P,TJTYPO		;Report
	JRST POPJ1

; To get table data from text
TJG1:	MOVSI Q,-TABCNT
	MOVE A,ASAVE		;Get back to the first non-space char in 1st line
	MOVE G,INDCNT		;Get character counter for first non-space
	SETZM TABMAX#

TJG2:	SETZ T,
TJG3:	SETZ H,
TJG4:	AOS T			;We start on the first char
	ILDB C,A
	CAIE C," "
	CAIN C,11
	JRST TJG8		
	CAIE C,15		;Must exit on CR
	AOBJN G,TJG4
	TRNN Q,777		;Were any fields found?
	JRST TJTYPO		;No, so report on margins
	CAMLE T,TABMAX
	JRST TJG15		;Not a normal tab field
	MOVE T,TABMAX		;Make last field as long as the max.
	HRLZM T,TABTAB(Q)
	JRST TJG15

;To count spaces or TABS to check field termination
TJG5:	AOS H
TJG6:	AOS T
TJG7:	ILDB C,A		;A space or TAB found, is there another one?
TJG8:	CAIE C," "		;Is it a space?
	JRST TJG9
	AOBJN G,TJG5
	JRST TJG15

TJG9:	CAIN C,11		;or a TAB?
	AOJA H,TJG7		;TABs do not count in G or T, but add to H
	CAIL H,TJSCNT		;Were there JSCNT or more spaces?
	JRST TJG13		;Yes, so at end of this TAB field
	AOBJN G,TJG3		;Single spaces allowed within fields
	JRST TJG15

TJG10:	OUTSTR [ASCIZ/ Only /]
	MOVEI A,TABCNT
	TYPDEC A
	OUTSTR [ASCIZ/ TABS allowed. /]
	JRST TJG15

TJG13:	CAMLE T,TABMAX
	MOVEM T,TABMAX
	HRLZM T,TABTAB(Q)	;Save field length
	AOBJP Q,TJG10
	AOBJN G,TJG2
TJG15:	MOVE TT,TPMAR
	PUSHJ P,TJADJ		;Adjust all tab values to reflect corrections
TJG18:	MOVEI Q,TABCNT
	SKIPG TABTAB(Q)
	SOJG Q,.-1
	HRRZ TT,TABTAB(Q)
	CAMLE TT,TRMAR
	MOVEM TT,TRMAR		;Correct to account for extended last tab
	POPJ P,

;  To report on TAB and TJ switch, margins and tabular settings
TJTYPO:	OUTSTR [ASCIZ/"T" /]
	MOVE T,TJSWTC
	SKIPGE TABFLG
	JRST [XCT SWNOTT(T)↔JRST TJTYP1]	;Different note for XTABLE
	XCT SWNOTE(T)			;OUTSTR appropiate note
	CAIE T,2
	JRST TJTYP1
	TYPDEC TPMARO
	OUTSTR [ASCIZ/) /]
TJTYP1:	SKIPL TBNUM
	JRST TJG18A
	OUTSTR [ASCIZ/Margins (P,L,R) are /]
	MOVSI Q,-3
	JRST TJG19A

TJG18A:	OUTSTR [ASCIZ/Margins (P,L,R,B) are /]
	MOVSI Q,-4		;Report values
	SKIPA
TJG19:	OUTSTR [ASCIZ /,/]
TJG19A:	TYPDEC TPMAR(Q)
	AOBJN Q,TJG19
	SKIPG TABTAB		;Are there any TABS?
	JRST TJG23
	MOVSI Q,-TABCNT
	SKIPLE TABTAB(Q)
	AOBJN Q,.-1
	ANDI Q,777
	OUTSTR [ASCIZ/;
  /]
	TYPDEC Q
	OUTSTR [ASCIZ/ fields /]
	MOVSI Q,-TABCNT
	SKIPA
TJG20:	OUTSTR [ASCIZ/,/]
	SETZ H,
	HLRZ T,TABTAB(Q)
TJG20A:	HLRZ TT,TABTAB+1(Q)
	CAME T,TT
	JRST TJG20B
	AOS H
	AOBJN Q,TJG20A
	
TJG20B:	JUMPE H,TJG20C
	AOS H			;The first one was not counted
	TYPDEC H		;Count of similar fields
	OUTSTR [ASCIZ/@/]
TJG20C:	TYPDEC T
	SKIPLE TABTAB+1(Q)
	AOBJN Q,TJG20
TJG21:	OUTSTR [ASCIZ/ indented /]
	MOVE T,TPMAR
	TYPDEC T
	MOVSI Q,-TABCNT
TJG22:	SKIPLE TABTAB+1(Q)
	OUTSTR [ASCIZ/,/]
	HRRZ T,TABTAB(Q)
	SKIPG TABTAB+1(Q)
	JRST TJG24
	TYPDEC T
	AOBJN Q,TJG22

TJG24:	CAML T,TRMAR
	JRST TJG25
	OUTSTR [ASCIZ/, text /]
	TYPDEC T
TJG25:	OUTSTR [ASCIZ/. /]
	POPJ P,

TJG23:	OUTSTR [ASCIZ/ No tabulation found./]
	POPJ P,
;BREAK JOIN

;To break a specified number of lines into fragments ≤BREAKV in length
BREAK:	TLZ F,JOINF		;Not to be a JOIN
	MOVEM A,JCNT		;Number of lines, default value is 1
	MOVE T,EXTPNT		;To read break length if specified
	MOVEM T,TYIPNT		;Set pointer.
	HRLI C,(<MOVEI C,>)
	MOVEM C,TYIINS
	SETZB A,C
BREAK0:	PUSHJ P,TYI		;Get first character if any.
	JRST BREAK4		;We are to use default value
	CAIN C," "
	JRST BREAK0		;Ignore an extra space in here.
BREAK1:	CAIG C,71
	CAIGE C,60
	JRST BREAK3
	IMULI A,12
	ADDI A,-"0"(C)
	PUSHJ P,TYI
	JRST BREAK2
	JRST BREAK1

BREAK2:	JUMPG A,BRK2A
	SORRY BREAK length of 0 not allowed.
	JRST POPJ1

BRK2A:	CAILE A,377770
	MOVEI A,377770		;This should be large enough!
	MOVEM A,BREAKV		;Break value is always sticky
BREAK4:	SKIPLE JCNT		;Non-positive arg means just tell default value
	JRST JOIN0		;BREAK something now
	OUTSTR [ASCIZ /Default BREAK length is now /]
	SETZM TYOPNT
	TYPDEC BREAKV
	OUTSTR [ASCIZ /. /]
	JRST POPJ1		;Abort on 0 or neg argument

BREAK3:	SORRY Only digits permitted in following arg.
	SETZM TYIPNT
	JRST POPJ1

;To join a specified number of lines into 1 continuous line of arbitrary max length
JOIN:	TRNN F,ARG
	MOVEI A,2
	JUMPG A,JOIN0A
	SORRY JOIN argument must be positive.
	JRST POPJ1		;Abort on 0 or neg argument

JOINPM:	SORRY Cannot JOIN or BREAK a non-text line.
	JRST POPJ1

JOIN0A:	MOVEM A,JCNT
	TLO F,JOINF		;Set JOIN flag
JOIN0:	TRNE F,ATTMOD		;Don't care about arrow line if doing attach buffer
	JRST JOIN0B
	TLNE F,PMLIN!OFFEND
	JRST JOINPM		;Current line is pagemark
JOIN0B:	PUSHJ P,ENDSET		;To guarentee that new line will be at the end of FS
	TLO F,NOCHK		;Don't CORE DOWN untill through
	TRNE F,ATTMOD		;Are we in ATTACH mode?
	SKIPA E,[JATAB]		;   Yes so put [JATAB] in E.
	MOVEI E,JPTAB		;   No so put [JPTAB] in E.
	HRRZ A,@JPT1(E)		;Put right of @ATTBUF or @ARRLIN in A
	MOVEM A,JPTR		;Address of link word for first line of text
	HLLZ Q,TXTFLG(A)	;Save flags
;Link up start of new area in place of the old
	HRRZ H,FSEND
	ADDI H,1
	TLNE F,JOINF
	JRST JOINB		;Join bypass
JOINA:	HRRZ T,TXTCNT(A)	;Get size of the line
	CAMLE T,BREAKV		;Is line short enough already?
	JRST JOINB		;No
	SETZ Q,			;Yes, next line cannot be ARRL
	HRRZ A,(A)		;Go to it
	MOVEM A,JPTR		;Reset for later FSGIVE
	CAME A,JETST(E)		;Are we at the end?
	SKIPGE TXTFLG(A)
	JRST JOINA1
	SOSLE JCNT		;or has count run out?
	JRST JOINA		;Maybe better luck next time
JOINA1:	PUSHJ P,ENDFIX
	TLZ F,NOCHK
	OUTSTR [ASCIZ /No lines broken. /]
	AOS (P)
	POPJ P,			;Nothing to do

JOINB:
LEG	HLLM Q,TXTFLG(H)	;Use old flags
	TLNE Q,ARRBIT		;May need to reset ARRLIN
	MOVEM H,ARRLIN
	TLNE Q,WINBIT		;and also WINLIN
	MOVEM H,WINLIN
	SETZ Q,
	MOVEM H,JLPT
	HLLZ TT,(A)		;Use the left half of old link for
LEG	MOVEM TT,(H)		;left half of the new link word, zero right
	HLRZ T,TT
 	HRRM H,(T)		;Fix earlier forward link to the new line
	AOS TT,TXTNUM
LEG	HRRM TT,TXTSER(H)	;Assign H new serial number
	ADD H,[440700,,LLDESC]	;Pointer for depositing text
	CAIN T,PAGE
	TRO F,UPDTXT		;This is the first line on the page
	MOVN B,BREAKV		;Set for BREAK
	TLNE F,JOINF
	MOVEI B,400000		;Set very large for JOIN
	HRLZS B
	SETZ G,
JOIN1A:	SETZ I,			;To accumulate counts for null line detection
JOIN1:	HRRZ T,TXTCNT(A)	;Is this a null line?
	JUMPE T,JOIN4		;Null line bypass
	MOVE D,A
	ADD D,[440700,,LLDESC]	;Pointer to read text
	ADD I,T
	JRST JOIN3

;Transfer text, counting chars and fixing up TABs
JOIN2:
LEG	IDPB C,H
JOIN3:	ILDB C,D
	CAIN C,11		;Is it a TAB?
	JRST JOIN5		;Yes
	CAIN C,15
	JRST JOIN4
	AOBJN B,JOIN2
JOIN2A:
LEG	IDPB C,H		;Not a CR so save it
	MOVE TT,D
	ILDB C,TT		;Sneak a look at next char
	CAIE C,15		;Is it a CR?
	JRST JOIN6A		;No, so there is something to break off
	TLO B,400000		;Nothing willl be left so make B neg
JOIN4:	AOS Q
;Test for end of text and fix up for next line
	HRRZ A,(A)		;Look at next line
	SKIPL TXTFLG(A)
	CAMN A,JETST(E)		;Are we at BOTSTR or ATTBUF?
	SETZM JCNT		;This is needed later
	SOSLE JCNT		;Have we joined the specified number of lines?
	TLNN F,JOINF		;Or is it a CR for a BREAK?
	JRST JOIN6		;Yes
	SOS @JLPTR(E)		;1 line removed from LINES or ATTNUM
	SOS @JCPTR(E)		;But correct CHARS or ATTSIZ now
	SOS @JCPTR(E)		;for both CR and LF that will be deleted
	JRST JOIN1

;Routine for fixing TABs
JOIN5:	ILDB C,D		;Yes
	CAIN C,40
	JRST .-2		;Eat original spaces
;	CAIE C,11		;Spaces should terminate in a TAB
;	OUTSTR [ASCIZ /TAB trouble, inspect text carefully for char omission. /]
;Now put in correct number of spaces for deposited position in line
LEG	IDPB C,H		;Deposit as initial TAB
	HRROI TT,-10
	IORI TT,(B)
	HRLS TT		;So that B-left is properly updated
	SUB B,TT
	ADDI G,(TT)
	MOVEI T,40
	JRST .+11(TT)
	REPEAT 10,<LEG	IDPB T,H>
	AOS G
	JUMPL B,JOIN2		;Jump if have room for more in this line
	JRST JOIN2A

;JOIN6 finishes off the line
JOIN6:	JUMPG I,JOIN6A		;Not a null line
	MOVEI C,40
LEG	IDPB C,H		;At least 1 char is required
	MOVSI B,-1		;Mark input line as used up, output line as empty
JOIN6A:	MOVEI C,15
LEG	IDPB C,H		;The CR
	MOVEI C,12
LEG	IDPB C,H		;And a LF
	TDZA C,C
LEG	IDPB C,H		;And a null
	TLNE H,760000
	JRST .-2
	MOVE T,JLPT
	ADDI G,2(B)
	HRLZS G
	ADDI G,(B)
LEG	MOVEM G,TXTCNT(T)	;Record char counts
;Text must be in ASCID
	ADDI T,LLDESC		;Get address of first text word
	MOVEI TT,1
	IORM TT,(T)		;Convert text words to ASCID
	CAIGE T,(H)
	AOJA T,.-2
	MOVEI TT,2(H)
	MOVSI T,TXTCOD
	FSFIX TT,T
	SKIPG JCNT		;Have we exhausted the input?
	JRST JOIN7		;Yes, (will always be so if here on a JOIN)
BREAK6:	MOVE T,JLPT		;We will need more space
	HRRZ H,FSEND
	ADDI H,1		;Get its start
	HRRM H,(T)		;and link it to last piece
LEG	HRLM T,(H)
	MOVEM H,JLPT
	MOVE T,B		;Save for test
	MOVN B,BREAKV		;Reset counters
	TRNN F,ARG!REL		;If no argument given to BREAK,
	MOVEI B,400000		; then make sure we don't break the line again
	HRLZS B
	SETZ G,
LEG	HRLM G,TXTFLG(H)	;Broken-off piece or next line cannot be ARRL
	AOS TT,TXTNUM
LEG	HRRM TT,TXTSER(H)
	ADD H,[440700,,LLDESC]
	JUMPL T,JOIN1A		;There was at a CR in original text so reset
	AOS @JLPTR(E)		;An extra line will be added
	AOS @JCPTR(E)		;And 2 extra chars
	AOS @JCPTR(E)
	JRST JOIN3

;And complete the links to the following text
JOIN7:	MOVE T,JLPT		;Now fix new right link
	HRRM A,(T)		;A references  next line
	HRLM T,(A)		;And backward link to the new line
	PUSHJ P,ENDFIX
;It should be safe to FSGIVE now, count is in Q
 	MOVE A,JPTR		;Get back address of first old line
	JUMPE Q,.+4
	PUSHJ P,FSGIVE		;And give up its space
	HRRZ A,(A)
	SOJG Q,.-2		;Do this for all the old lines
	TRO F,WRITE!DSPALL
	TLZ F,NOCHK
	TLNN F,JOINF		;No message on a break
	JRST JEXIT(E)
	MOVE T,JLPT		;Restore T value
	HRRZ B,TXTCNT(T)	;and check final length of joined line
	SETZM TYOPNT
	OUTSTR [ASCIZ /Line now has /]
	TYPDEC B
	OUTSTR [ASCIZ / chars. /]
	AOS (P)
	JRST JEXIT(E)
;SHIFTY
;This routine tests all lines of text that are in the ATTACH buffer for
;the presence of a space or a TAB in the first chararacter as a prelude
;to the execution of left shift.
SHIFTY:	HRRZ D,[ATTBUF]		;Needed for completion test.
	MOVE T,(D)		;Get starting location
SHFTY1:	MOVE A,[350700,,3(T)]	;Pointer to the first word of text
	LDB C,A			;and the first character
	CAIE C,40		;Is it a space?
	CAIN C,11		;or maybe a TAB?
	JRST .+2		;Good!
	JRST SHFTY2		;Too bad, give message and return
	CAIN D,(T)		;Are we through?
	AOJA P,SHFTY3		;Yes, so use second return
	MOVE T,(T)		;Go to next line of text
	JRST SHFTY1		;and go on
SHFTY2:	SORRY One line (at least) is as far as it can go.
SHFTY3:	POPJ P,